package mth.masterimp;

import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;

import rs.fon.whibo.GC.component.DistanceMeasure.DistanceMeasure;

/*
 * only TRUE Constraints - representing the must-links - are used
 */
public class Constraints {
	
	/*
	 * Die umfangreichste der verfügbaren Klassen. Hier werden nach den in der zugehörigen
	 * Masterarbeit vorgestellten Methoden die Nebenbedingungen erhoben. Krititsche Punkte stellen
	 * vor allem die getFarthest**** Methoden dar. Hier erfolgt die Suche nach den als nächstes zu
	 * erfragenden Datenelementen.
	 */

	public static final double QUERY_PERCENT=2.0;
	
	private int[][] pairs;
	private int pairCount;
	private Question q;
	private DataRepresentator dr;
	private Neighborhood[] neighborhoods;
	private String technique;
	private Random rgen;
	private GammaCluster[] gammaCluster;
	private boolean appendRandom;
	private int allowedQueries;
	private int[] exSet;
	
	Constraints(DataRepresentator d, String tech, boolean appRand) {
		technique=tech;
		dr=d;
		q=new Question(d);
		rgen = new Random();
		pairCount=0;
		appendRandom=appRand;
		allowedQueries=-1;
		exSet = new int[0];
	}
	
	Constraints(DataRepresentator d, String tech, int queries, boolean appRand) {
		technique = tech;
		dr=d;
		q=new Question(d);
		if (queries!=-1) {
			pairs=new int[2][queries];
			allowedQueries=queries;
		} else {
			allowedQueries=-1;
		}
		rgen = new Random();
		pairCount=0;
		appendRandom=appRand;
		exSet = new int[0];
	}
	
	private void addAsPair(int x, int y) {
		if (pairs==null) {
			pairs = new int[2][dr.getValueMatrix().getNumberOfRows()];
		}
		if (!arePaired(x, y)) {
			pairs[0][pairCount]=x;
			pairs[1][pairCount]=y;
			pairCount++;
		}
	}
	
	private boolean arePaired(int x, int y) {
		if (pairs != null) {
			for (int a=0; a<pairCount; a++) {
				if (pairs[0][a]==x || pairs[0][a]==y) {
					if (pairs[1][a]==x || pairs[1][a]==y) {
						return true;
					}
				}
			}
		}
		return false;
	}
	
	private void basuConsolidate(int maxQuestionCount) {
		if (q.getAmountOfAllQueries()>maxQuestionCount) {
			System.out.println("Das war nicht gelungen - keine Consolidate-Phase!");
		}
		//the stopper and halt method is not very smart, but it 
		//catches up the case, that unlimited random numbers are tested
		//but there are no more useful questions to ask or the
		//probability of detecting a good case is too low
		int stopper=0;
		int halt=0;
		while (q.getAmountOfAllQueries()<maxQuestionCount && exSet.length<dr.getValueMatrix().getNumberOfRows()-1) {
			if (halt<100) {
				if (stopper==0) {
					stopper=q.getAmountOfAllQueries();
				} else {
					if (stopper==q.getAmountOfAllQueries()) {
						halt++;
					} else {
						halt=0;
						stopper=q.getAmountOfAllQueries();
					}
				}
			} else {
				return;
			}
			for (int a=0; a<neighborhoods.length; a++) {
				neighborhoods[a].nullCRep();
				neighborhoods[a].calculateClusterRepresentative();
			}
			int next=nextRandom();
			Map <Integer,Double> m = new LinkedHashMap<Integer, Double>();
			int[] orderOfNeighborhoods = new int[neighborhoods.length];
			try {
				DistanceMeasure d = dr.generateDistanceMeasure(dr.getDistanceMeasure(), null);
				double distance=0.0;
				for (int a=0; a<neighborhoods.length; a++) {
					distance=d.calculateDistance(Tools.extractDoubleArrayFromDataRow(dr.getValueMatrix().getRow(next)), Tools.extractDoubleArrayFromDataRow(dr.getValueMatrix().getRow(neighborhoods[a].getCRepRowID())));
					m.put(neighborhoods[a].getNumber(), distance);
					orderOfNeighborhoods[a]=neighborhoods[a].getNumber();
				}
				
				for (int a=0; a<m.size()-1; a++) {
					for (int b=a+1; b<m.size(); b++) {
						if (m.get(neighborhoods[a].getNumber())>m.get(neighborhoods[b].getNumber())) {
							int helper=0;
							helper=orderOfNeighborhoods[a];
							orderOfNeighborhoods[a]=orderOfNeighborhoods[b];
							orderOfNeighborhoods[b]=helper;
						}
					}
				}
				boolean questionStopper=false;
				for (int a=0; a<orderOfNeighborhoods.length; a++) {
					if (!questionStopper && !arePaired(next, neighborhoods[orderOfNeighborhoods[a]].getCRepRowID()) && q.isNewQuestion(next, neighborhoods[orderOfNeighborhoods[a]].getCRepRowID())) {
						boolean testi = q.ask(next, neighborhoods[orderOfNeighborhoods[a]].getCRepRowID());
						if (testi) {
							addAsPair(next, neighborhoods[orderOfNeighborhoods[a]].getCRepRowID());
							neighborhoods[orderOfNeighborhoods[a]].addMember(next);
							questionStopper=true;
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	private void basuExplore() {
		int[] x=new int[2];
		
		int[] exploreSet = new int[0];
		for (int a=0; Neighborhood.getNumberOfNeighborhoods()<dr.getK(); a++) {
			if (a==0) {
				x[0]=nextRandom();
				x[1]=getFarthestElement(x[0]);
			} else {
				x=getFarthestElements(exploreSet);
			}
			if (exploreSet.length==0) {
				exploreSet = new int[2];
				exploreSet[0]=x[0];
				exploreSet[1]=x[1];
			} else {
				boolean contains = false;
				for (int b=0; b<exploreSet.length; b++) {
					contains=(exploreSet[b]==x[0] && exploreSet[b]==x[1] && !contains)?true:false;
				}
				if (!contains) {
					int[] helper = new int[exploreSet.length+1];
					for (int b=0; b<exploreSet.length; b++)
						helper[b]=exploreSet[b];
					helper[exploreSet.length]=x[1];
					exploreSet = new int[helper.length];
					exploreSet = helper;
				}					
			}
			if(q.ask(x[0], x[1])) {
				addAsPair(x[0],x[1]);
				if (neighborhoods==null || neighborhoods.length==0) {
					neighborhoods = new Neighborhood[1];
					neighborhoods[0] = new Neighborhood(Neighborhood.getNumberOfNeighborhoods());
					neighborhoods[0].addMember(x[0]);
					neighborhoods[0].addMember(x[1]);
				} else {
					int x_0=getNeighborhoodOfMember(x[0]);
					int x_1=getNeighborhoodOfMember(x[1]);
					if (x_0==x_1 && x_0 != -1) {
						//nothing to do
					} else if (x_0 == -1 && x_1 != -1) {
						neighborhoods[x_1].addMember(x[0]);
					} else if (x_0 != -1 && x_1 == -1) {
						neighborhoods[x_0].addMember(x[1]);
					} else if (x_0 != -1 && x_1 != -1 && x_0 != x_1) {
						neighborhoods[x_0].combineNeighborhoods(neighborhoods[x_0], neighborhoods[x_1]);
						removeNeighborhood(neighborhoods[x_1]);
					} else if (x_0 == -1 && x_1 == -1) {
						if (Neighborhood.getNumberOfNeighborhoods()<dr.getK()) {
							newNeighborhood();
							neighborhoods[neighborhoods.length-1].addMember(x[0]);
							neighborhoods[neighborhoods.length-1].addMember(x[1]);
						}
					}
				}
			} else {
				if (neighborhoods==null || neighborhoods.length==0) {
					neighborhoods = new Neighborhood[2];
					neighborhoods[0]=new Neighborhood(Neighborhood.getNumberOfNeighborhoods());
					neighborhoods[0].addMember(x[0]);
					neighborhoods[1]=new Neighborhood(Neighborhood.getNumberOfNeighborhoods());
					neighborhoods[1].addMember(x[1]);
				} else {
					int x_0=getNeighborhoodOfMember(x[0]);
					int x_1=getNeighborhoodOfMember(x[1]);
					if (x_0 == -1) {
						if (Neighborhood.getNumberOfNeighborhoods()<dr.getK()) {
							newNeighborhood();
							neighborhoods[neighborhoods.length-1].addMember(x[0]);
						}
					} //else --> nothing
					if (x_1 == -1) {
						if (Neighborhood.getNumberOfNeighborhoods()<dr.getK()) {
							newNeighborhood();
							neighborhoods[neighborhoods.length-1].addMember(x[1]);
						}
					} //else --> nothing
				}
			}
		}
	}
	
	public void buildAllConstraints() {
		int maxQuestionCount=(allowedQueries==-1)?(int)(dr.getValueMatrix().getNumberOfRows()*QUERY_PERCENT):allowedQueries;
		if (technique.equals("B")) {
			basuExplore();
			basuConsolidate(maxQuestionCount);
		} else if (technique.equals("m")) {
			meCombineClusters();
			meExploreClusters(maxQuestionCount);
			if (appendRandom) {
				if (q.getAmountOfAllQueries()<maxQuestionCount) {
					meDoRandomQueries(maxQuestionCount);
				}
			}
		}
	}
	
	private void getAllNewNeighborhoods() {
		String[] colNames = dr.getValueMatrix().getColumnNames();
		int colLabel=0;
		double[] cluster = new double[0];
		for (int a=0; a<colNames.length; a++) {
			if (colNames[a].equals("cluster"))
				colLabel=a;
		}
		
		for (int a=0; a<dr.getValueMatrix().getNumberOfRows(); a++) {
			if (cluster.length==0) {
				cluster=new double[1];
				cluster[0]=dr.getValueMatrix().getRow(a).getValue(colLabel);
			}
			if (!Tools.doubleArrayContains(cluster,dr.getValueMatrix().getRow(a).getValue(colLabel))) {
				double[] helper = new double[cluster.length+1];
				for (int b=0; b<cluster.length; b++) {
					helper[b]=cluster[b];
				}
				helper[cluster.length]=dr.getValueMatrix().getRow(a).getValue(colLabel);
				cluster = new double[helper.length];
				for (int b=0; b<helper.length; b++) {
					cluster[b]=helper[b];
				}
			}
		}
		for (int a=0; a<cluster.length; a++) {
			for (int b=a+1; b<cluster.length; b++) {
				if (cluster[a]>cluster[b]) {
					double helper = cluster[a];
					cluster[a]=cluster[b];
					cluster[b]=helper;
				}
			}
		}
		if (neighborhoods==null || neighborhoods.length==0) {
			neighborhoods = new Neighborhood[cluster.length];
		}
		newNeighborhoods();
		for (int a=0; a<neighborhoods.length; a++) {
			for (int b=0; b<dr.getValueMatrix().getNumberOfRows(); b++) {
				if (cluster[a]==dr.getValueMatrix().getRow(b).getValue(colLabel)) {
					neighborhoods[a].addMember(b);
				}
			}
			neighborhoods[a].nullCRep();
			neighborhoods[a].calculateClusterRepresentative();
		}
	}
	
	public int getFarthestElement(int x) {
		double[] dataRow = dr.getDistanceMatrixRow(x);
		double maximumDistance=Double.NEGATIVE_INFINITY;
		int maximumDistancePosition=-1;
		
		for (int a=0; a<dataRow.length; a++) {
			if (dataRow[a]>maximumDistance && !Tools.intArrayContains(exSet, a) && exSet.length<dataRow.length) {
				maximumDistance = dataRow[a];
				maximumDistancePosition = a;
			}
		}
		if (maximumDistancePosition==-1) {
			System.out.println("entferntestes Element konnte nicht gefunden werden, getFarthestElement");
			System.out.println(dr.getDistanceMeasure()+" key:"+x);
		} else {
			exSet=Tools.addIntegerToArray(exSet, maximumDistancePosition);
		}
		return maximumDistancePosition;
	}
	
	public int getFarthestElementOfGammaCluster(int x, int gc) {
		double[] distMatrRow = dr.getDistanceMatrixRow(x);
		double maximumDistance=Double.NEGATIVE_INFINITY;
		int maximumDistancePosition=-1;

		//cleaning up in memory of explored elements
		
		for (int a=0; a<distMatrRow.length; a++) {
			if (!Tools.intArrayContains(gammaCluster[gc].getExploredMember(), a) && distMatrRow[a]>maximumDistance && Tools.intArrayContains(gammaCluster[gc].getMember(), a)) {
				maximumDistance = distMatrRow[a];
				maximumDistancePosition = a;
			}
		}
		
		if (maximumDistancePosition==-1) {
			System.out.println("entferntestes Element konnte nicht gefunden werden");
		} else {
//			gammaCluster[gc].setMemberExploredByName(maximumDistancePosition);
		}
		return maximumDistancePosition;
	}
	
	public int[] getFarthestElements(int[] exploreSet) {
		Map <Integer, Integer> m = new LinkedHashMap<Integer, Integer>();
		Map <Integer, Double> d	= new LinkedHashMap<Integer, Double>();
		int newMember=0;
		int key=-1;
		double minGlobalDist=-1.0;
		int localFarthestElement=-1;
		
		for (int a=0; a<exploreSet.length; a++) {
			localFarthestElement=getFarthestElement(exploreSet[a]);
			m.put(exploreSet[a], localFarthestElement);
			d.put(exploreSet[a],dr.getDistanceMatrixRow(localFarthestElement)[exploreSet[a]]);
		}
		
		int negativeHits=0;
		for (int a=0; a<m.size(); a++) {
			if (Tools.intArrayContains(exploreSet, m.get(exploreSet[a]))) {
				negativeHits++;
			} else {
				if (minGlobalDist==-1.0) {
					minGlobalDist=d.get(exploreSet[a]);
					newMember=m.get(exploreSet[a]);
					key = exploreSet[a];
				} else {
					if (minGlobalDist>d.get(exploreSet[a])) {
						minGlobalDist=d.get(exploreSet[a]);
						newMember=m.get(exploreSet[a]);
						key = exploreSet[a];
					}
				}
			}
		}
		int[] pair = new int[2];
		
		//dirty rescue method...should be seen as a point on the TODO list
		//do it like the rescue with isExploredElement in GammaCluster methods?
		if (negativeHits==m.size() || key==-1) {
			int dirtyRescue = getMeanElementOfExploreSet(exploreSet);
			while (Tools.intArrayContains(exploreSet, dirtyRescue)) {
				dirtyRescue = nextRandom();
				exploreSet=Tools.addIntegerToArray(exploreSet, dirtyRescue);
				dirtyRescue = getMeanElementOfExploreSet(exploreSet);
			}
				
			exploreSet=Tools.addIntegerToArray(exploreSet, dirtyRescue);
			pair=getFarthestElements(exploreSet);
		} else {
			pair[0]=key;
			pair[1]=newMember;
		}
		return pair;
	}
	
	private int[] getFarthestElementsOfGammaCluster(int[] exploreSet, int gc) {
		int[] pair = new int[2];
		Map <Integer, Integer> valueValue = new LinkedHashMap<Integer, Integer>();
		Map <Integer, Double> valueDistance = new LinkedHashMap<Integer, Double>();
		int actObj=-1;
		for (int a=0; a<exploreSet.length; a++) {
			actObj=getFarthestElementOfGammaCluster(exploreSet[a], gc);
			valueValue.put(exploreSet[a], actObj);
			valueDistance.put(exploreSet[a], dr.getDistanceMatrix()[exploreSet[a]][actObj]);
		}
		int newMember=-1;
		int key=-1;
		double minDistance=Double.NEGATIVE_INFINITY;
		for (int a=0; a<valueValue.size(); a++) {
			if (a==0) {
				key=exploreSet[a];
				newMember=valueValue.get(exploreSet[a]);
				minDistance=valueDistance.get(exploreSet[a]);
			} else {
				if (minDistance>valueDistance.get(exploreSet[a])) {
					key=exploreSet[a];
					newMember=valueValue.get(exploreSet[a]);
					minDistance=valueDistance.get(exploreSet[a]);
				}
			}
		}
		pair[0]=key;
		pair[1]=newMember;
		if (newMember != -1) {
			gammaCluster[gc].setMemberExploredByName(newMember);
		} else {
			System.out.println("huh...terribly wrong");
		}
		
		return pair;
	}
	
	private int getMeanElementOfExploreSet(int[] exploreSet) {
		double[] mean = new double[dr.getValueMatrix().getNumberOfColumns()-dr.getValueMatrix().getNumberOfSpecialColumns()];
		int meanestElement=-1;
		for (int a=0; a<mean.length; a++) {
			for (int b=0; b<exploreSet.length; b++) {
				mean[a]+=Double.parseDouble(dr.getValueMatrix().getCell(exploreSet[b], a));
			}
			mean[a]=mean[a]/exploreSet.length;
		}
		try {
			DistanceMeasure d = dr.generateDistanceMeasure(dr.getDistanceMeasure(),null);
			int minDistPos=-1;
			double actDist = -1.0;
			double minDist=-1.0;
			for (int a=0; a<dr.getValueMatrix().getNumberOfRows(); a++) {
				if (minDistPos==-1) {
					minDist=d.calculateDistance(Tools.extractDoubleArrayFromDataRow(dr.getValueMatrix().getRow(a)), mean);
					minDistPos=a;
				} else {
					actDist=d.calculateDistance(Tools.extractDoubleArrayFromDataRow(dr.getValueMatrix().getRow(a)), mean);
					if (minDist>actDist) {
						minDist=actDist;
						minDistPos=a;
					}
				}
			}
			if (minDistPos==-1)
				minDistPos=-2;
			meanestElement=minDistPos;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return meanestElement;
	}
	
	public int getNeighborhoodOfMember (int memb) {
		int x_0=-1;
		for (int b=0; b<neighborhoods.length; b++) {
			if (neighborhoods[b].containsMember(memb))
				x_0=b;
		}
		return x_0;
	}
	
	public Neighborhood[] getNeighborhoods() {
		return neighborhoods;
	}
	
	public int getPairCount() {
		return pairCount;
	}
	
	public int[][] getPairs() {
		return pairs;
	}
	
	private void meCombineClusters() {
		getAllNewNeighborhoods();
		//ugh...that hits hard
		//I suggest, that k is the real number of classes hidden in the data
		//regarding to that the user knows the real k
		//...but in the actual case we use labeled data, so this isn't critical
		for (int a=0; a<dr.getK(); a++) {
			for (int b=a+1; b<neighborhoods.length; b++) {
				if (a!=b) {
					boolean combine = q.ask(neighborhoods[a].getCRepRowID(), neighborhoods[b].getCRepRowID());
					//TODO: here you need to add the centers as a pair of constraints, and add them
					//to the explored Set and later to the gammaCluster explored Elements
					//--> regarding to the statistics, there are just missing some count pairs
					//but luckily for further steps the real questioned pairs of the Question class are used
					if (combine) {
						neighborhoods[a].combineNeighborhoods(neighborhoods[a], neighborhoods[b]);
						removeNeighborhood(neighborhoods[b]);
						b--;
					}
				}
			}
		}
		
		gammaCluster = new GammaCluster[neighborhoods.length];
		for (int a=0; a<gammaCluster.length; a++) {
			neighborhoods[a].nullCRep();
			neighborhoods[a].calculateClusterRepresentative();
			gammaCluster[a]= new GammaCluster(neighborhoods[a].getMember(),neighborhoods[a].getCRepRowID());
			for (int b=0; neighborhoods[a].getMember().length>1; b++) {
				if (b>neighborhoods[a].getMember().length-1)
					b=0;
				if (neighborhoods[a].getMember()[b]!=neighborhoods[a].getCRepRowID()) {
					neighborhoods[a].removeMember(neighborhoods[a].getMember()[b]);
					b--;
				}
			}
		}
	}
	
	private void meExploreClusters(int maxQuestionCount) {
		if (q.getAmountOfAllQueries()>maxQuestionCount) {
			System.out.println("Schade, die Fragen sind bereits alle verbraucht. "+
		"Es gibt wohl keine meExploreClusters() Phase mehr.");
		}
		
		int[] exploreSet=new int[1];
		int[] testSet = new int[2];
		if (q.getAmountOfAllQueries()<maxQuestionCount && exploreSet.length<dr.getValueMatrix().getNumberOfRows()-1) {
			for (int a=0; a<gammaCluster.length; a++) {
				exploreSet[0]=gammaCluster[a].getCentroid();
				gammaCluster[a].setMemberExploredByName(gammaCluster[a].getCentroidID());
				testSet[0]=exploreSet[0];
				int doUntil=(2*(dr.getValueMatrix().getNumberOfColumns()-dr.getValueMatrix().getNumberOfSpecialColumns())<(gammaCluster[a].getNumberOfMembers()-1))?
						2*(dr.getValueMatrix().getNumberOfColumns()-dr.getValueMatrix().getNumberOfSpecialColumns()):(gammaCluster[a].getNumberOfMembers()-1);
				for (int b=0; b<doUntil && gammaCluster[a].getNumberOfMembers()>gammaCluster[a].getExploredMember().length && exploreSet.length<gammaCluster[a].getNumberOfMembers(); b++) {
					testSet=getFarthestElementsOfGammaCluster(exploreSet,a);
					boolean eSetContainsAlready=Tools.intArrayContains(exploreSet, testSet[1]);
					if (eSetContainsAlready) {
						int nearestElement = dr.getNearestElementTo(testSet[1]);
						if (Tools.intArrayContains(exploreSet, nearestElement)) {
							return; //rethink and search for a good solution
						} else {
							if (!Tools.intArrayContains(gammaCluster[a].getMember(), nearestElement)) {
								if (gammaCluster[a].getMember().length<=exploreSet.length)
									return;
							}
							testSet[1]=nearestElement;
						}
					}
					
					if (q.getAmountOfAllQueries()<maxQuestionCount) {
						if (q.ask(testSet[0],testSet[1])) {
							addAsPair(testSet[0], testSet[1]);
						}
						exploreSet = Tools.addIntegerToArray(exploreSet, testSet[1]);
						neighborhoods[a].addMember(testSet[1]);
					} else {
						System.out.println("no more questions, but you are not at the end of the cluster exploration.");
					}
				}
				exploreSet=new int[1];
			}
		}
	}
	
	private void meDoRandomQueries(int maxQuestionCount) {
		basuConsolidate(maxQuestionCount);
	}
	
	private void newNeighborhood() {
		if (neighborhoods==null || neighborhoods.length==0) {
			neighborhoods = new Neighborhood[1];
			neighborhoods[0] = new Neighborhood(Neighborhood.getNumberOfNeighborhoods());
		} else {
			Neighborhood[] helper = new Neighborhood[neighborhoods.length+1];
			for (int b=0; b<neighborhoods.length; b++)
				helper[b]=neighborhoods[b];
			helper[neighborhoods.length]=new Neighborhood(Neighborhood.getNumberOfNeighborhoods());
			neighborhoods = new Neighborhood[helper.length];
			neighborhoods=helper;
		}
	}
	
	private void newNeighborhoods() {
		if (neighborhoods==null || neighborhoods.length==0) {
			neighborhoods = new Neighborhood[1];
			neighborhoods[0] = new Neighborhood(Neighborhood.getNumberOfNeighborhoods());
		} else {
			for (int a=0; a<neighborhoods.length; a++) {
				neighborhoods[a] = new Neighborhood(Neighborhood.getNumberOfNeighborhoods());
			}
		}
	}
	
	private int nextRandom() {
		int rreturn=rgen.nextInt()%dr.getValueMatrix().getNumberOfRows();
		return (rreturn<0)?-rreturn:rreturn;
	}
	
	public int getAmountOfAllQueries() {
		return q.getAmountOfAllQueries();
	}
	
	public int getAmountOfNegativeQueries() {
		return q.getAmountOfNegativeQueries();
	}
	
	public int getAmountOfConstraints() {
		return pairCount;
	}
	
	public void printCQGc(String file) {
		q.print(file);
		
		String outputString="";
		
//		outputString+="Eigenschaften der Nachbarschaften\n";
//		outputString+="Anzahl Nachbarschaften: "+neighborhoods.length+"\n";
//		outputString+="Anzahl der Member pro Nachbarschaft:\n";
//		for (int a=0; a<neighborhoods.length; a++) {
//			outputString+="Nachbarschaft "+a+":"+neighborhoods[a].getMember().length+"\n";
//			outputString+="zentrales Element: "+neighborhoods[a].getCRepRowID()+"\n";
//		}
//		try {
//			FileWriter fw = new  FileWriter(file+"_neighborhoods_prop", false);
//			fw.write(outputString);
//			fw.close();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
		
		//neighborhoods member
		outputString="";
		for (int a=0; a<neighborhoods.length; a++) {
			for (int b=0; b<neighborhoods[a].getMember().length; b++) {
				if (b==neighborhoods[a].getMember().length-1) {
					outputString+=neighborhoods[a].getMember()[b];
				} else {
					outputString+=neighborhoods[a].getMember()[b]+",";
				}
			}
			outputString+="\n";
		}
		try {
			FileWriter fw = new  FileWriter(file+"_neighborhoods_member", false);
			fw.write(outputString);
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		//print GammaCluster
		if (technique.equals("m")) {
			outputString="";
			for (int a=0; a<gammaCluster.length; a++) {
				outputString+="Gamma Cluster Zentroid: "+gammaCluster[a].getCentroid()+"\n";
				outputString+=gammaCluster[a].printGammaCluster()+"\n";
			}
			try {
				FileWriter fw = new  FileWriter(file+"_gammaCluster", false);
				fw.write(outputString);
				fw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void removeNeighborhood(Neighborhood n) {
		boolean removed=false;
		for (int a=0; a<neighborhoods.length-1; a++) {
			if (removed) {
				neighborhoods[a]=neighborhoods[a+1];
				neighborhoods[a].updateNumber(a);
			} else {
				if (neighborhoods[a]==n) {
					neighborhoods[a]=neighborhoods[a+1];
					neighborhoods[a].updateNumber(a);
					removed=true;
				}
			}
		}
		Neighborhood[] helper = new Neighborhood[neighborhoods.length-1];
		for (int a=0; a<helper.length; a++) {
			helper[a]=neighborhoods[a];
		}
		neighborhoods = new Neighborhood[helper.length];
		neighborhoods = helper;
	}
}
